/*
 * Copyright (c) 2006-2018, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2018-01-26     armink       the first version
 */

#include "fal_def.h"
#include <fal.h>

#if FAL_USING_SUFD
#include <sfud.h>

#ifndef FAL_USING_NOR_FLASH_DEV_NAME
#define FAL_USING_NOR_FLASH_DEV_NAME             "norflash0"
#endif

static int init(void);
static int read(long offset, uint8_t *buf, size_t len);
static int write(long offset, const uint8_t *buf, size_t len);
static int erase(long offset, size_t len);

static sfud_flash_t sfud_dev = NULL;
static uint32_t     sfud_dev_num = 0;
struct fal_flash_dev sfud_nor_flash0 =
{
    .name       = FAL_USING_NOR_FLASH_DEV_NAME, //default name
    .addr       = 0,
    .len        = 8 * 1024 * 1024,
    .blk_size   = 4096,
    .ops        = {init, read, write, erase},
    .write_gran = 1
};

static int init(void)
{
    /* bare metal platform */
    sfud_dev_num = sfud_get_device_num();   //SFUD_FLASH_DEVICE_INDEX_MAX
    sfud_dev = (sfud_flash_t)sfud_get_device_table();
    if (NULL == sfud_dev)
    {
        return -1;
    }
    
    if(sfud_dev->init_ok == false)
    {
        if(sfud_device_init(sfud_dev))
        {
            return -2;
        }
    }
    
    /* update the flash chip information */
    sfud_nor_flash0.blk_size = sfud_dev->chip.erase_gran;
    sfud_nor_flash0.len = sfud_dev->chip.capacity;
    LOG_I("sfud name:%s.",sfud_dev->name);
    LOG_I("chip size:%u \t block_size:%u.",sfud_nor_flash0.len, sfud_nor_flash0.blk_size);
    return 0;
}

static int read(long offset, uint8_t *buf, size_t len)
{
    LOG_ASSERT(sfud_dev);
    LOG_ASSERT(sfud_dev->init_ok);
    
    sfud_read(sfud_dev, sfud_nor_flash0.addr + offset, len, buf);

    return len;
}

static int write(long offset, const uint8_t *buf, size_t len)
{
    LOG_ASSERT(sfud_dev);
    LOG_ASSERT(sfud_dev->init_ok);
    
    if (sfud_write(sfud_dev, sfud_nor_flash0.addr + offset, len, buf) != SFUD_SUCCESS)
    {
        return -1;
    }

    return len;
}

static int erase(long offset, size_t len)
{
    LOG_ASSERT(sfud_dev);
    LOG_ASSERT(sfud_dev->init_ok);
    
    if (sfud_erase(sfud_dev, sfud_nor_flash0.addr + offset, len) != SFUD_SUCCESS)
    {
        return -1;
    }

    return len;
}
#endif /* FAL_USING_SFUD_PORT */

